////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   ReverbManager.cpp
//  Version:     v1.00
//  Created:     22/2/2006 by Tomas.
//  Compilers:   Visual Studio.NET
//  Description: Base implementation of a ReverbManager.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "ReverbManager.h"
#include "SoundCVars.h"
#include "IRenderer.h"
#include "IRenderAuxGeom.h"
#include "IAudioDevice.h"
#include "IEntitySystem.h"
#include "ISerialize.h"
#include "IGameFramework.h"
#include "SoundSystem.h"
#include "Sound.h"

#include <IPhysics.h>

//////////////////////////////////////////////////////////////////////////
// Initialization
//////////////////////////////////////////////////////////////////////////

float				CReverbManager::m_fObstructionTestResults[DIRECTIONS_COUNT] = {0.0f};
int					CReverbManager::m_nSentIdx = 0;

CReverbManager::CReverbManager()
{
	m_pAudioDevice			= NULL;
	m_pSoundSystem			= NULL;
	m_bForceUnderwater	= false;
	
	string sFullFileName;
	sFullFileName = REVERB_PRESETS_FILENAME_XML;

	LoadFromXML(sFullFileName.c_str(), false);
	m_ReverbEnable = false;

	m_nLastEax=REVERB_PRESET_OFF;	

	CRYSOUND_REVERB_PROPERTIES PropsIn = CRYSOUND_REVERB_PRESET_INDOOR;
	m_EAXIndoorPreset = PropsIn;

	CRYSOUND_REVERB_PROPERTIES pPropsOut = CRYSOUND_REVERB_PRESET_OUTDOOR;
	m_EAXOutdoorPreset = pPropsOut;

	CRYSOUND_REVERB_PROPERTIES pPropsOff = CRYSOUND_REVERB_PRESET_OFF;
	m_EAXOffPreset = pPropsOff;

	m_sTempPreset.EAX =	m_EAXOutdoorPreset;
	m_sTempPreset.sPresetName = "Mix";

	m_sTempEaxPreset.pReverbPreset = &m_sTempPreset;

	m_pLastEAXProps = NULL;
	m_vecActiveReverbPresetAreas.reserve(4);
	m_vecActiveReverbPresetAreas.clear();
	m_bInside = false;
	m_bNeedUpdate = true;

	m_sIndoorMix	= "IndoorMix";
	m_sOutdoorMix = "OutdoorMix";
	
	m_v3ObstructionTestVecs[0] = Vec3(0.0f, 0.0f, 1.0f),	// Top vector
	m_v3ObstructionTestVecs[1] = Vec3(0.0f, 1.0f, 0.0f),	// Front vector
	m_v3ObstructionTestVecs[2] = Vec3(0.0f, -1.0f, 0.0f),	// Rear vector
	m_v3ObstructionTestVecs[3] = Vec3(1.0f, 0.0f, 0.0f),	// Right vector
	m_v3ObstructionTestVecs[4] = Vec3(-1.0f, 0.0f, 0.0f),	// Left vector

	m_v3Origin.zero();

	if(gEnv->pPhysicalWorld)
		gEnv->pPhysicalWorld->AddEventClient(EventPhysRWIResult::id, OnObstructionTest, 1);

	m_nEchoDSPEnabled	= 0;
}

CReverbManager::~CReverbManager()
{
	m_ReverbPresets.clear();

	if (gEnv->pPhysicalWorld)
		gEnv->pPhysicalWorld->RemoveEventClient(EventPhysRWIResult::id, OnObstructionTest, 1);
}

void CReverbManager::Init(IAudioDevice *pAudioDevice, CSoundSystem* pSoundSystem)
{
	assert (pAudioDevice);
	assert (pSoundSystem);
	m_pAudioDevice = pAudioDevice;
	m_pSoundSystem = pSoundSystem;
}

bool CReverbManager::SelectReverb(int nReverbType) 
{ 
	m_bNeedUpdate = true;
	if (nReverbType == 0)
	{
		m_ReverbEnable = false;
		m_vecActiveReverbPresetAreas.clear();
		Update(false);
	}
	else
		m_ReverbEnable = true;
	
	return true; 
}

void CReverbManager::Reset()
{
	stl::free_container(m_vecActiveReverbPresetAreas);
}

void CReverbManager::Release()
{
	Reset();
}

bool CReverbManager::SetData(SReverbInfo::Data *pReverbData)
{

	m_ReverbPresets.clear();
	m_vecActiveReverbPresetAreas.clear();

	if (!pReverbData)
		return false;

	int i;

	//////////////////////////////////////////////////////////////////////////
	// Set Presets.

	m_ReverbPresets.reserve(pReverbData->nPresets);
	for (i = 0; i < pReverbData->nPresets; i++)
	{
		SReverbInfo::SReverbPreset NewPreset;
		NewPreset.sPresetName = pReverbData->pPresets[i].sPresetName;
		NewPreset.EAX = pReverbData->pPresets[i].EAX;
		m_ReverbPresets.push_back(NewPreset);
	}
	return true;
	
}

//////////////////////////////////////////////////////////////////////////
void CReverbManager::LoadPresetFromXML(XmlNodeRef const& pNodePreset, SReverbInfo::SReverbPreset* const pPreset)
{
	// The values below need to be translated to match the FMOD internal scale.
	int nValue   = 0;
	float fValue = 0.0f;

	pPreset->sPresetName = pNodePreset->getTag();
	XmlNodeRef pNodeParameter(pNodePreset->findChild("nMasterLevel"));

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", nValue);
		pPreset->EAX.nRoom = nValue * 100;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"nMasterLevel\"");
	}

	pNodeParameter = pNodePreset->findChild("fDecayTime");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fDecayTime = fValue / 1000.0f;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fDecayTime\"");
	}

	pNodeParameter = pNodePreset->findChild("fHFDecayRatio");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fDecayHFRatio = fValue;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fHFDecayRatio\"");
	}

	pNodeParameter = pNodePreset->findChild("fPreDelay");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fReflectionsDelay = fValue / 1000.0f;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fPreDelay\"");
	}

	pNodeParameter = pNodePreset->findChild("fLateDelay");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fReverbDelay = fValue / 1000.0f;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fLateDelay\"");
	}

	pNodeParameter = pNodePreset->findChild("nEarlyReflections");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", nValue);
		pPreset->EAX.nReflections = nValue * 100;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"nEarlyReflections\"");
	}

	pNodeParameter = pNodePreset->findChild("nLateReflections");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", nValue);
		pPreset->EAX.nReverb = nValue * 100;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"nLateReflections\"");
	}

	pNodeParameter = pNodePreset->findChild("fDiffusion");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fDiffusion = fValue;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fDiffusion\"");
	}

	pNodeParameter = pNodePreset->findChild("fDensity");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fDensity = fValue;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fDensity\"");
	}

	pNodeParameter = pNodePreset->findChild("nHFGain");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", nValue);
		pPreset->EAX.nRoomHF = nValue * 100;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"nHFGain\"");
	}

	pNodeParameter = pNodePreset->findChild("nLFGain");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", nValue);
		pPreset->EAX.nRoomLF = nValue * 100;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"nLFGain\"");
	}

	pNodeParameter = pNodePreset->findChild("fHFCrossover");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fHFReference = fValue;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fHFCrossover\"");
	}

	pNodeParameter = pNodePreset->findChild("fLFCrossover");

	if (pNodeParameter)
	{
		pNodeParameter->getAttr("value", fValue);
		pPreset->EAX.fLFReference = fValue;
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"fLFCrossover\"");
	}

	pNodeParameter = pNodePreset->findChild("EchoDSP");

	if (pNodeParameter)
	{
		XmlNodeRef oEchoDSPChildNode = pNodeParameter->findChild("fDelay");
		oEchoDSPChildNode->getAttr( "value", pPreset->EchoDSP.fDelay );
		oEchoDSPChildNode = pNodeParameter->findChild("fDecayRatio");
		oEchoDSPChildNode->getAttr( "value", pPreset->EchoDSP.fDecayRatio);
		oEchoDSPChildNode = pNodeParameter->findChild("fDryMix");
		oEchoDSPChildNode->getAttr( "value", pPreset->EchoDSP.fDryMix );
		oEchoDSPChildNode = pNodeParameter->findChild("fWetMix");
		oEchoDSPChildNode->getAttr( "value", pPreset->EchoDSP.fWetMix );
	}
	else
	{
		CRY_ASSERT_MESSAGE(0, "ReverbManager: failed to find parameter \"EchoDSP\"");
	}
}

//////////////////////////////////////////////////////////////////////////
bool CReverbManager::LoadFromXML( const char *sFilename,bool bAddData )
{
	// Loading.
	if (!bAddData)
	{
		//Unload();
	}

	XmlNodeRef root = GetISystem()->LoadXmlFromFile( sFilename );

	if (!root)
	{
		GetISystem()->Warning( VALIDATOR_MODULE_SYSTEM,VALIDATOR_WARNING,VALIDATOR_FLAG_SOUND,sFilename,
			"Reverb description XML file %s failed to load",sFilename );
		return false;
	}

	// Iterate reverb presets
	m_ReverbPresets.reserve(root->getChildCount());
	for (int i = 0; i < root->getChildCount(); i++)
	{
		XmlNodeRef nodeTheme = root->getChild(i);
		
		//if (nodeTheme->isTag("Preset"))
		{
			SReverbInfo::SReverbPreset NewPreset;
			LoadPresetFromXML( nodeTheme, &NewPreset );
			m_ReverbPresets.push_back(NewPreset);

		}
	}

	//m_bDataLoaded = true;

	return true;
}



//////////////////////////////////////////////////////////////////////////
// Information
//////////////////////////////////////////////////////////////////////////

// writes output to screen in debug
void CReverbManager::DrawInformation(IRenderer* pRenderer, float xpos, float ypos)
{
	//ActiveEaxPresetAreasIter It=m_vecActiveEaxPresetAreas.begin();
	//pRenderer->Draw2dLabel(xpos, ypos, 1.5, fColorGreen, false, "EAX - %s",(*It).sPresetName);
	float fColorGreen[4] ={0.0f, 1.0f, 0.0f, 0.7f};
	float fColorGray[4]	 ={0.3f, 0.3f, 0.3f, 0.7f};
	float fColorTemp[4]	 ={0.0f, 0.0f, 0.0f, 0.7f};
	float fColorRed[4]	 ={1.0f, 0.0f, 0.0f, 0.7f};

	if (!m_ReverbEnable)
	{
		pRenderer->Draw2dLabel(xpos, ypos, 1.35f, fColorGray, false, "Reverb disabled");
		ypos+=11;
		return;
	}


	ActiveReverbPresetAreasIterConst  IterEnd = m_vecActiveReverbPresetAreas.end();
	for (ActiveReverbPresetAreasIterConst  It=m_vecActiveReverbPresetAreas.begin(); It!=IterEnd; ++It)
	{
		float *pCurColor = fColorGreen;

		if ((*It).bFullEffectWhenInside)
			pCurColor = fColorRed;

		fColorTemp[0] = (*It).fWeight * pCurColor[0] + (1.0f - (*It).fWeight) * fColorGray[0];
		fColorTemp[1] = (*It).fWeight * pCurColor[1] + (1.0f - (*It).fWeight) * fColorGray[1];
		fColorTemp[2] = (*It).fWeight * pCurColor[2] + (1.0f - (*It).fWeight) * fColorGray[2];

		pRenderer->Draw2dLabel(xpos, ypos, 1.35f, fColorTemp, false, "EAX - %s",(*It).pReverbPreset->sPresetName.c_str());

		ypos+=11;
	}
}


//////////////////////////////////////////////////////////////////////////
// Management
//////////////////////////////////////////////////////////////////////////

// needs to be called regularly
void CReverbManager::Update(bool const bInside)
{
	if (m_bNeedUpdate && m_ReverbEnable)
	{
		FUNCTION_PROFILER( GetISystem(),PROFILE_SOUND );

		m_bNeedUpdate = false;

		if (!m_bForceUnderwater && g_SoundCVars.g_nGameReverbManagerPause == 0)
		{
			// Verifying Reverb Values enabled/disables
			bool Checkresults = true;
			float SumOfWeight = 0;
			m_bInside = bInside;

			// if there is only one Preset just interpolate directly with its weight
			if (m_vecActiveReverbPresetAreas.size()==1)
			{
				ActiveReverbPresetAreasIterConst It= m_vecActiveReverbPresetAreas.begin();
				SumOfWeight = (*It).fWeight;
				m_sTempEaxPreset = (*It);
			}
			else
			{
				ActiveReverbPresetAreasIter ItEnd = m_vecActiveReverbPresetAreas.end();
				for (ActiveReverbPresetAreasIter It=m_vecActiveReverbPresetAreas.begin(); It!=ItEnd; ++It)
				{
					// Copy first element to the temp preset
					if (It==m_vecActiveReverbPresetAreas.begin())
					{
						m_sTempEaxPreset = (*It);
					}
					else // start interpolating at the 2nd element
					{
						// calculate the sum of the weight
						SumOfWeight = m_sTempEaxPreset.fWeight + (*It).fWeight;
						if (SumOfWeight>0) 
						{
							float BlendRatio = 0;
							BlendRatio = (*It).fWeight / SumOfWeight;
							EAX3ListenerInterpolate(&m_sTempEaxPreset.pReverbPreset->EAX, &((*It).pReverbPreset->EAX), BlendRatio, &m_sTempEaxPreset.pReverbPreset->EAX, Checkresults);

							m_sTempEaxPreset.fWeight = BlendRatio;
							//gEnv->pLog->LogToConsole("setting Weight %f Interpolate", BlendRatio);
						}
					}
				}
			}

			// if the weighted sum of effect has not reached 100% then "fill up" with basic preset
			if (SumOfWeight < 1) 
			{
				EAX3ListenerInterpolate(&(m_bInside ? m_EAXIndoorPreset : m_EAXOutdoorPreset), &m_sTempEaxPreset.pReverbPreset->EAX, SumOfWeight, &m_sTempEaxPreset.pReverbPreset->EAX, Checkresults);
			}
		}
		else if (g_SoundCVars.g_nGameReverbManagerPause)
		{
			CRYSOUND_REVERB_PROPERTIES pPropsOff = CRYSOUND_REVERB_PRESET_OFF;
			m_sTempEaxPreset.pReverbPreset->EAX  = pPropsOff;
		}
		else if (m_bForceUnderwater)
		{
			CRYSOUND_REVERB_PROPERTIES pPropsOut = CRYSOUND_REVERB_UNDERWATER;
			m_sTempEaxPreset.pReverbPreset->EAX  = pPropsOut;
		}
	}
}

//////////////////////////////////////////////////////////////////////////
bool CReverbManager::SetListenerReverb(SOUND_REVERB_PRESETS nPreset, CRYSOUND_REVERB_PROPERTIES *tpProps, uint32 nFlags)
{
	bool bSuccess = false;

	if (m_ReverbEnable)
	{
		m_bForceUnderwater = nPreset == REVERB_PRESET_UNDERWATER;

		if ((nFlags & FLAG_SOUND_OUTDOOR) != 0)
		{
			gEnv->pSoundSystem->Log(eSLT_Message, "<Sound> Setting global EAX outdoor");

			m_bForceUnderwater = false;
			m_EAXOutdoor.EAX   = *tpProps;
		}

		bSuccess = true;
	}

	return bSuccess;
}

// Preset management
bool CReverbManager::RegisterReverbPreset(char const* const pcPresetName/* =NULL */, CRYSOUND_REVERB_PROPERTIES const* const pReverbProperties/* =NULL */, CRYSOUND_ECHO_PROPERTIES const* const pEchoProperties/* =NULL */)
{
	//GUARD_HEAP;
	//FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );

	if(!m_ReverbEnable)
		return false;

	m_bNeedUpdate = true;

	//gEnv->pLog->LogToConsole("Registered Preset %s", sPresetName);

	assert(pcPresetName && pcPresetName[0]);
	assert(pReverbProperties && pEchoProperties);

	// add this Preset to the vector of Presets or update it if its already in there
	bool bPresetfound = false;
	for(ReverbPresetsIter It=m_ReverbPresets.begin(); It!=m_ReverbPresets.end(); ++It)
	{
		// update
		if((*It).sPresetName == pcPresetName)
		{
			(*It).EAX				= *pReverbProperties;
			(*It).EchoDSP		= *pEchoProperties;
			bPresetfound		= true;
			break;
		}
	}

	if(!bPresetfound)
	{
		SReverbInfo::SReverbPreset NewPreset;
		NewPreset.EAX					= *pReverbProperties;
		NewPreset.EchoDSP			= *pEchoProperties;
		NewPreset.sPresetName = pcPresetName;

		m_ReverbPresets.push_back(NewPreset);
	}

	return true;
}

bool CReverbManager::UnregisterReverbPreset(const char *sPresetName)
{
	//GUARD_HEAP;
	//	FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );

	if (!m_ReverbEnable)
		return false;

	m_bNeedUpdate = true;

	//gEnv->pLog->Log("Unregistered Preset %s", sPresetName);

	assert( sPresetName[0] );

	bool bPresetfound = false;
	do 
	{
		bPresetfound = UnregisterWeightedReverbEnvironment(sPresetName);
	} while (bPresetfound);

	bool bWeightedfound = false;
	for (ReverbPresetsIter It=m_ReverbPresets.begin(); It!=m_ReverbPresets.end(); ++It)
	{
		if ((*It).sPresetName == sPresetName)
		{
			// Delete the active Preset from the vector
			m_ReverbPresets.erase(It);
			bWeightedfound = true;
			break;
		}
	}
	return bWeightedfound;

}


//! Registers an EAX Preset Area with the current blending weight (0-1) as being active
//! morphing of several EAX Preset Areas is done internally
//! Registering the same Preset multiple time will only overwrite the old one
//bool CReverbManager::RegisterWeightedReverbEnvironment(const char *sPresetName, CRYSOUND_REVERB_PROPERTIES *pProps, bool bFullEffectWhenInside, int nFlags)
bool CReverbManager::RegisterWeightedReverbEnvironment(const char *sPresetName, EntityId RegID, bool bFullEffectWhenInside, uint32 nFlags)
{
	//GUARD_HEAP;
	//FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );

	if (!m_ReverbEnable)
		return false;

	m_bNeedUpdate = true;

	//gEnv->pLog->LogToConsole("Registered Preset %s", sPresetName);

	//assert(sPresetName != "");
	assert( sPresetName[0] );

	// add this Preset to the vector of active Presets or update it if its already in there
	SReverbInfo::SReverbPreset* pPreset = NULL;

	for (ReverbPresetsIter It=m_ReverbPresets.begin(); It!=m_ReverbPresets.end(); ++It)
	{
		if ((*It).sPresetName == sPresetName)
		{
			// Delete the active Preset from the vector
			pPreset = &(*It);
			break;
		}
	}

	// couldnt find Preset
	if (!pPreset)
		return false;

	bool bWeightedfound = false;

	for (ActiveReverbPresetAreasIter  It=m_vecActiveReverbPresetAreas.begin(); It!=m_vecActiveReverbPresetAreas.end(); ++It)
	{
		if ((*It).pReverbPreset->sPresetName == sPresetName && (*It).RegID == RegID)
		{
			(*It).bFullEffectWhenInside = bFullEffectWhenInside;
			(*It).pReverbPreset				  = pPreset;
			bWeightedfound							= true;
			break;
		}
	}

	//assert(!Presetfound);

	if (!bWeightedfound) 
	{
		SReverbInfo::SWeightedReverbPreset NewWeighted;

		NewWeighted.pReverbPreset = pPreset;
		NewWeighted.fWeight = 0; // always start with 0
		NewWeighted.bFullEffectWhenInside = bFullEffectWhenInside;
		NewWeighted.RegID = RegID;

		m_vecActiveReverbPresetAreas.push_back(NewWeighted);
	}
	return true;
}


//! Updates an EAX Preset Area with the current blending ratio (0-1)
bool CReverbManager::UpdateWeightedReverbEnvironment(const char *sPresetName, EntityId RegID, float fWeight)
{
	//GUARD_HEAP;
	//FUNCTION_PROFILER( GetISystem(),PROFILE_SOUND );

	if (!m_ReverbEnable)
		return false;

	m_bNeedUpdate = true;

	//gEnv->pLog->Log("Update Preset %s", sPresetName);

	//assert(sPresetName != "");
	assert( sPresetName[0] );
	assert(fWeight >= 0 && fWeight <= 1);

	// update this Preset to the vector of active Presets or add if its not in there yet
	bool bWeightedfound = false;
	for (ActiveReverbPresetAreasIter It=m_vecActiveReverbPresetAreas.begin(); It!=m_vecActiveReverbPresetAreas.end(); ++It)
	{
		if ((*It).pReverbPreset->sPresetName == sPresetName && (*It).RegID == RegID)
		{
			(*It).fWeight = fWeight;
			bWeightedfound = true;
			break;
		}
	}
	//assert(Presetfound);

	return bWeightedfound;
}


//! Unregisters an active EAX Preset Area 
bool CReverbManager::UnregisterWeightedReverbEnvironment(const char *sPresetName, EntityId RegID)
{
	//GUARD_HEAP;
//	FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );

	if (!m_ReverbEnable)
		return false;

	m_bNeedUpdate = true;

	//gEnv->pLog->Log("Unregistered Preset %s", sPresetName);

	//assert(sPresetName != "");
	assert( sPresetName[0] );

	bool bWeightedfound = false;
	for (ActiveReverbPresetAreasIter It=m_vecActiveReverbPresetAreas.begin(); It!=m_vecActiveReverbPresetAreas.end(); ++It)
	{
		// remove all occurences if RedID == 0, because then the whole preset gets removed
		if ((*It).pReverbPreset->sPresetName == sPresetName && ((*It).RegID == RegID || RegID == 0 || (*It).RegID == 0))
		{
			// Delete the active Preset from the vector
			m_vecActiveReverbPresetAreas.erase(It);
			bWeightedfound = true;
			break;
		}
	}
	//assert(Presetfound);

	return bWeightedfound;
}


//! Gets current EAX listener environment.
bool CReverbManager::GetCurrentReverbEnvironment(SOUND_REVERB_PRESETS &nPreset, CRYSOUND_REVERB_PROPERTIES &Props)
{
	nPreset=m_nLastEax;
	if (m_pLastEAXProps)
		memcpy(&Props,m_pLastEAXProps,sizeof(CRYSOUND_REVERB_PROPERTIES));
	else
		memset(&Props,0,sizeof(CRYSOUND_REVERB_PROPERTIES));

	return (true);
}

//////////////////////////////////////////////////////////////////////////
//ISound* CReverbManager::GetSound( tSoundID nSoundId )
//{
//	SRegisteredSound *pSoundSlot = FindRegisteredSound(nSoundId);
//	if (pSoundSlot)
//		return pSoundSlot->pSound;
//	return 0;
//}

//////////////////////////////////////////////////////////////////////////
CReverbManager::SRegisteredSound* CReverbManager::FindRegisteredSound( tSoundID nSoundId )
{
	RegisteredSoundsVec::iterator ItEnd = m_Sounds.end();
	for (RegisteredSoundsVec::iterator It = m_Sounds.begin(); It != ItEnd; ++It)
	{
		SRegisteredSound &slot = (*It);
		if (slot.nSoundID == nSoundId)
			return &slot;
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
bool CReverbManager::RemoveRegisteredSound( tSoundID nSoundId )
{
	RegisteredSoundsVec::iterator ItEnd = m_Sounds.end();
	for (RegisteredSoundsVec::iterator It = m_Sounds.begin(); It != ItEnd; ++It)
	{
		SRegisteredSound &slot = (*It);
		if (slot.nSoundID == nSoundId)
		{
			m_Sounds.erase(It);
			return true;
		}
	}
	return false;
}
/*
bool CReverbManager::RegisterSound(ISound *pSound)
{
	SRegisteredSound* pNewSound = FindRegisteredSound(pSound->GetId());

	if (!pNewSound)
	{
		SRegisteredSound NewSound;

		NewSound.pSound = pSound;
		NewSound.nSoundID = pSound->GetId();

		m_Sounds.push_back(NewSound);
	}


	//m_Sounds.push_back(NewSound);

	//gEnv->pEntitySystem->GetAreaManager()->TriggerSound(pSound);

	return true;
}
*/
//int  CReverbManager::GetReverbInstance(ISound *pSound) const
//{
//	return 0;
//}
	
float CReverbManager::GetEnvironment(Vec3 const& rPosition)
{
	int unsigned const nMaxResults = 10;
	SAreaManagerResult Results[nMaxResults];

	bool bResult = gEnv->pEntitySystem->GetAreaManager()->QueryAreas(rPosition, Results, nMaxResults, true);

	int nPriority = -1; 
	float fEnvironment = 0;
	//char *sReverbPreset = NULL;
	bool bQuery = false;

	// Iterate through all areas vPos is inside
	for (unsigned int nAreaIndex = 0; nAreaIndex < nMaxResults; ++nAreaIndex)
	{
		if (Results[nAreaIndex].pArea)
		{
			if (Results[nAreaIndex].bInside)
			{
				int nEntityNum = Results[nAreaIndex].pArea->GetEntityAmount();
				for (int i=0; i<nEntityNum; ++i)
				{
					EntityId EID = Results[nAreaIndex].pArea->GetEntityByIdx(i);
					IEntity* pEntity = gEnv->pEntitySystem->GetEntity(EID);

					// is this a ReverbVolume
					if (pEntity && (strcmp(pEntity->GetClass()->GetName(),"ReverbVolume") == 0))
					{
						SmartScriptTable props;
						IScriptTable* pScriptTable = pEntity->GetScriptTable();

						if (pScriptTable)
						{
							if (pScriptTable->GetValue("Properties", props) )
							{
								int bEnable = 0;
								float fThisEnvironment = 0;
								bQuery = props->GetValue("bEnabled", bEnable);
								bQuery = props->GetValue("Environment", fThisEnvironment);
								//bQuery = props->GetValue("reverbpresetReverbPreset", sReverbPreset);

								if (bEnable != 0 && nPriority < Results[nAreaIndex].pArea->GetPriority())
								{
									fEnvironment = fThisEnvironment;
									nPriority = Results[nAreaIndex].pArea->GetPriority();
								}
							}
						}
					}
				}
			}
		}
		(void)bQuery;
	}

	return fEnvironment;
}

//bool CReverbManager::RegisterPlayer(EntityId PlayerID)
//{
//	return true;
//}
//
//bool CReverbManager::UnregisterPlayer(EntityId PlayerID)
//{
//	return true;
//}

//////////////////////////////////////////////////////////////////////////
void CReverbManager::OnSoundEvent( ESoundCallbackEvent event,ISound *pSound )
{
	switch (event) {
	case SOUND_EVENT_ON_STOP:
		{
			RemoveRegisteredSound(pSound->GetId());
			break;
		}

	case SOUND_EVENT_ON_LOAD_FAILED:
		break;
	}
}
/*
//////////////////////////////////////////////////////////////////////////
void CReverbManager::OnAreaManagerEvent( EEntityEvent event, EntityId TriggerEntityID, IArea *pArea )
{
	if (!pArea)
		return;

	IListener *pListener = gEnv->pSoundSystem->GetListener(TriggerEntityID);
	bool bIsCamera = false;
	
	if (!pListener)
	{
		IEntity* pTriggerEntity = NULL;
		pTriggerEntity = gEnv->pEntitySystem->GetEntity(TriggerEntityID);
		bIsCamera = strcmp(pTriggerEntity->GetClass()->GetName(), "CameraSource") == 0;
	}

	int nNum = pArea->GetEntityAmount();

	for (int i=0; i<nNum; ++i)
	{
		EntityId ID = pArea->GetEntityByIdx(i);
		IEntity* pEntity = gEnv->pEntitySystem->GetEntity(ID);
		
		if (pEntity)
		{
			pEntity->GetClass()->GetName();
		}

	}

	if (pListener || bIsCamera)
	{
		switch (event) 
		{
		case ENTITY_EVENT_ENTERAREA:
			break;
		case ENTITY_EVENT_LEAVEAREA:
			break;
		case ENTITY_EVENT_ENTERNEARAREA:
			break;
		case ENTITY_EVENT_LEAVENEARAREA:
			break;
		case ENTITY_EVENT_MOVEINSIDEAREA:
			break;
		case ENTITY_EVENT_MOVENEARAREA:
			break;

		default:
			break;
		}
	}


}
*/

/***********************************************************************************************\
*
* Definition of the EAXMorph function - EAX3ListenerInterpolate
*
\***********************************************************************************************/

/*
EAX3ListenerInterpolate
lpStart			- Initial EAX 3 Listener parameters
lpFinish		- Final EAX 3 Listener parameters
flRatio			- Ratio Destination : Source (0.0 == Source, 1.0 == Destination)
lpResult		- Interpolated EAX 3 Listener parameters
bCheckValues	- Check EAX 3.0 parameters are in range, default = false (no checking)
*/
bool CReverbManager::EAX3ListenerInterpolate(CRYSOUND_REVERB_PROPERTIES *lpStart, CRYSOUND_REVERB_PROPERTIES *lpFinish,
																					 float flRatio, CRYSOUND_REVERB_PROPERTIES *lpResult, bool bCheckValues)
{
	if (bCheckValues)
	{
		if (!CheckReverbProperties(lpStart) || !CheckReverbProperties(lpFinish))
		{
			return false;
		}
	}

	if (flRatio >= 1.0f)
	{
		memcpy(lpResult, lpFinish, sizeof(CRYSOUND_REVERB_PROPERTIES));
		return true;
	}
	else if (flRatio <= 0.0f)
	{
		memcpy(lpResult, lpStart, sizeof(CRYSOUND_REVERB_PROPERTIES));
		return true;
	}

	float const flInvRatio = (1.0f - flRatio);

	// Master level
	if (lpStart->nRoom == lpFinish->nRoom)
		lpResult->nRoom = lpStart->nRoom;
	else
		lpResult->nRoom = (int)( ((float)lpStart->nRoom * flInvRatio) + ((float)lpFinish->nRoom * flRatio) );

	// Decay Time
	if (lpStart->fDecayTime == lpFinish->fDecayTime)
		lpResult->fDecayTime = lpStart->fDecayTime;
	else
		lpResult->fDecayTime = (float)expf( (logf(lpStart->fDecayTime) * flInvRatio) + (logf(lpFinish->fDecayTime) * flRatio) );

	// Decay HF Ratio
	if (lpStart->fDecayHFRatio == lpFinish->fDecayHFRatio)
		lpResult->fDecayHFRatio = lpStart->fDecayHFRatio;
	else
		lpResult->fDecayHFRatio = (float)expf( (logf(lpStart->fDecayHFRatio) * flInvRatio) + (logf(lpFinish->fDecayHFRatio) * flRatio) );

	// Reflections Delay
	if (lpStart->fReflectionsDelay == lpFinish->fReflectionsDelay)
		lpResult->fReflectionsDelay = lpStart->fReflectionsDelay;
	else
		lpResult->fReflectionsDelay = (float)expf( (logf(lpStart->fReflectionsDelay+0.0001f) * flInvRatio) + (logf(lpFinish->fReflectionsDelay+0.0001f) * flRatio) );

	// Reverb Delay
	if (lpStart->fReverbDelay == lpFinish->fReverbDelay)
		lpResult->fReverbDelay = lpStart->fReverbDelay;
	else
		lpResult->fReverbDelay = (float)expf( (logf(lpStart->fReverbDelay+0.0001f) * flInvRatio) + (logf(lpFinish->fReverbDelay+0.0001f) * flRatio) );

	// Reflections
	if (lpStart->nReflections == lpFinish->nReflections)
		lpResult->nReflections = lpStart->nReflections;
	else
		lpResult->nReflections = (int)( ((float)lpStart->nReflections * flInvRatio) + ((float)lpFinish->nReflections * flRatio) );

	// Reverb
	if (lpStart->nReverb == lpFinish->nReverb)
		lpResult->nReverb = lpStart->nReverb;
	else
		lpResult->nReverb = (int)( ((float)lpStart->nReverb * flInvRatio) + ((float)lpFinish->nReverb * flRatio) );

	// Diffusion
	if (lpStart->fDiffusion == lpFinish->fDiffusion)
		lpResult->fDiffusion = lpStart->fDiffusion;
	else
		lpResult->fDiffusion = (lpStart->fDiffusion * flInvRatio) + (lpFinish->fDiffusion * flRatio);

	// Density
	if (lpStart->fDensity == lpFinish->fDensity)
		lpResult->fDensity = lpStart->fDensity;
	else
		lpResult->fDensity = (lpStart->fDensity * flInvRatio) + (lpFinish->fDensity * flRatio);

	// HF gain
	if (lpStart->nRoomHF == lpFinish->nRoomHF)
		lpResult->nRoomHF = lpStart->nRoomHF;
	else
		lpResult->nRoomHF = (int)( ((float)lpStart->nRoomHF * flInvRatio) + ((float)lpFinish->nRoomHF * flRatio) );

	// LF gain
	if (lpStart->nRoomLF == lpFinish->nRoomLF)
		lpResult->nRoomLF = lpStart->nRoomLF;
	else
		lpResult->nRoomLF = (int)( ((float)lpStart->nRoomLF * flInvRatio) + ((float)lpFinish->nRoomLF * flRatio) );

	// HF Reference
	if (lpStart->fHFReference == lpFinish->fHFReference)
		lpResult->fHFReference = lpStart->fHFReference;
	else
		lpResult->fHFReference = (float)expf( (logf(lpStart->fHFReference) * flInvRatio) + (logf(lpFinish->fHFReference) * flRatio) );

	// LF Reference
	if (lpStart->fLFReference == lpFinish->fLFReference)
		lpResult->fLFReference = lpStart->fLFReference;
	else
		lpResult->fLFReference = (float)expf( (logf(lpStart->fLFReference) * flInvRatio) + (logf(lpFinish->fLFReference) * flRatio) );

	// Clamp Delays
	if (lpResult->fReflectionsDelay > CRYVERB_REFLECTIONS_DELAY_MAX)
		lpResult->fReflectionsDelay = CRYVERB_REFLECTIONS_DELAY_MAX;

	if (lpResult->fReverbDelay > CRYVERB_REVERB_DELAY_MAX)
		lpResult->fReverbDelay = CRYVERB_REVERB_DELAY_MAX;

	return true;
}

/*
EchoDSPInterpolate
rEchoPropertiesStart	- Initial EAX 3 Listener parameters
rEchoPropertiesFinish	- Final EAX 3 Listener parameters
fBlendRatio						- Ratio Destination : Source (0.0 == Source, 1.0 == Destination)
rEchoPropertiesResult	- Interpolated EAX 3 Listener parameters
*/
bool CReverbManager::EchoDSPInterpolate(CRYSOUND_ECHO_PROPERTIES const& rEchoPropertiesStart,
																				CRYSOUND_ECHO_PROPERTIES const& rEchoPropertiesFinish,
																				float fBlendRatio,
																				CRYSOUND_ECHO_PROPERTIES& rEchoPropertiesResult)
{
	float fInvRatio = 0.0f;

	if(fBlendRatio >= 1.0f)
	{
		rEchoPropertiesResult = rEchoPropertiesFinish;
		return true;
	}
	else if (fBlendRatio <= 0.0f)
	{
		rEchoPropertiesResult = rEchoPropertiesStart;
		return true;
	}

	fInvRatio = (1.0f - fBlendRatio);

	// Delay
	if(rEchoPropertiesStart.fDelay == rEchoPropertiesFinish.fDelay)
		rEchoPropertiesResult.fDelay = rEchoPropertiesStart.fDelay;
	else
		rEchoPropertiesResult.fDelay = (rEchoPropertiesStart.fDelay * fInvRatio) + (rEchoPropertiesFinish.fDelay * fBlendRatio);

	// DecayRatio
	if(rEchoPropertiesStart.fDecayRatio == rEchoPropertiesFinish.fDecayRatio)
		rEchoPropertiesResult.fDecayRatio = rEchoPropertiesStart.fDecayRatio;
	else
		rEchoPropertiesResult.fDecayRatio = (rEchoPropertiesStart.fDecayRatio * fInvRatio) + (rEchoPropertiesFinish.fDecayRatio * fBlendRatio);

	// DryMix
	if(rEchoPropertiesStart.fDryMix == rEchoPropertiesFinish.fDryMix)
		rEchoPropertiesResult.fDryMix = rEchoPropertiesStart.fDryMix;
	else
		rEchoPropertiesResult.fDryMix = (rEchoPropertiesStart.fDryMix * fInvRatio) + (rEchoPropertiesFinish.fDryMix * fBlendRatio);

	// WetMix
	if(rEchoPropertiesStart.fWetMix == rEchoPropertiesFinish.fWetMix)
		rEchoPropertiesResult.fWetMix = rEchoPropertiesStart.fWetMix;
	else
		rEchoPropertiesResult.fWetMix = (rEchoPropertiesStart.fWetMix * fInvRatio) + (rEchoPropertiesFinish.fWetMix * fBlendRatio);

	return true;
}

/*
CheckReverbProperties
Checks that the parameters in the CRYSOUND_REVERB_PROPERTIES structure are in-range.
*/
bool CReverbManager::CheckReverbProperties(CRYSOUND_REVERB_PROPERTIES const* const pProperties)
{
	if ((pProperties->nRoom < CRYVERB_ROOM_MIN) || (pProperties->nRoom > CRYVERB_ROOM_MAX))
	{
		return false;
	}

	if ((pProperties->nRoomHF < CRYVERB_ROOM_HF_MIN) || (pProperties->nRoomHF > CRYVERB_ROOM_HF_MAX))
	{
		return false;
	}

	if ((pProperties->nRoomLF < CRYVERB_ROOM_LF_MIN) || (pProperties->nRoomLF > CRYVERB_ROOM_LF_MAX))
	{
		return false;
	}

	if ((pProperties->fDecayTime < CRYVERB_DECAY_TIME_MIN) || (pProperties->fDecayTime > CRYVERB_DECAY_TIME_MAX))
	{
		return false;
	}

	if ((pProperties->fDecayHFRatio < CRYVERB_DECAY_HF_RATIO_MIN) || (pProperties->fDecayHFRatio > CRYVERB_DECAY_HF_RATIO_MAX))
	{
		return false;
	}

	if ((pProperties->nReflections < CRYVERB_REFLECTIONS_MIN) || (pProperties->nReflections > CRYVERB_REFLECTIONS_MAX))
	{
		return false;
	}

	if ((pProperties->fReflectionsDelay < CRYVERB_REFLECTIONS_DELAY_MIN) || (pProperties->fReflectionsDelay > CRYVERB_REFLECTIONS_DELAY_MAX))
	{
		return false;
	}

	if ((pProperties->nReverb < CRYVERB_REVERB_MIN) || (pProperties->nReverb > CRYVERB_REVERB_MAX))
	{
		return false;
	}

	if ((pProperties->fReverbDelay < CRYVERB_REVERB_DELAY_MIN) || (pProperties->fReverbDelay > CRYVERB_REVERB_DELAY_MAX))
	{
		return false;
	}

	if ((pProperties->fHFReference < CRYVERB_HF_REFERENCE_MIN) || (pProperties->fHFReference > CRYVERB_HF_REFERENCE_MAX))
	{
		return false;
	}

	if ((pProperties->fLFReference < CRYVERB_LF_REFERENCE_MIN) || (pProperties->fLFReference > CRYVERB_LF_REFERENCE_MAX))
	{
		return false;
	}

	if ((pProperties->fDiffusion < CRYVERB_DIFFUSION_MIN) || (pProperties->fDiffusion > CRYVERB_DIFFUSION_MAX))
	{
		return false;
	}

	if ((pProperties->fDensity < CRYVERB_DENSITY_MIN) || (pProperties->fDensity > CRYVERB_DENSITY_MAX))
	{
		return false;
	}

	return true;
}

//defines a distance function on ReverbProperties 
float CReverbManager::Distance(CRYSOUND_REVERB_PROPERTIES *lpProp1, CRYSOUND_REVERB_PROPERTIES *lpProp2)
{
	return abs(lpProp1->fDecayTime - lpProp2->fDecayTime);
}

void CReverbManager::SerializeState( TSerialize ser )
{
	string sTempName;

	if (ser.IsWriting())
	{
		// active moods
		int nActiveReverbsNum = m_vecActiveReverbPresetAreas.size();
		ser.Value("ReverbCount",nActiveReverbsNum);

		ActiveReverbPresetAreasIter  ItEnd = m_vecActiveReverbPresetAreas.end();
		for (ActiveReverbPresetAreasIter  It=m_vecActiveReverbPresetAreas.begin(); It!=ItEnd; ++It)
		{
			ser.BeginGroup("ActiveReverb");

			sTempName = (*It).pReverbPreset->sPresetName.c_str();
			ser.Value("ReverbName", sTempName);
			ser.Value("Weight",(*It).fWeight);
			ser.Value("EffectInside",(*It).bFullEffectWhenInside);
			ser.Value("RegID", (*It).RegID);

			ser.EndGroup();
		}
	}
	else
	{
		int nActiveReverbsNum = 0;
		ser.Value("ReverbCount",nActiveReverbsNum);

		for (int i=0; i<nActiveReverbsNum; ++i)
		{
			ser.BeginGroup("ActiveReverb");

			ser.Value("ReverbName",sTempName);
			SReverbInfo::SReverbPreset* pPreset = NULL;

			ReverbPresetsIter ItEnd = m_ReverbPresets.end();
			for (ReverbPresetsIter It=m_ReverbPresets.begin(); It!=ItEnd; ++It)
			{
				if ((*It).sPresetName == sTempName.c_str() )
				{
					pPreset = &(*It);
					break;
				}
			}

			if (pPreset) // reverb exist
			{
				SReverbInfo::SWeightedReverbPreset NewWeighted;

				NewWeighted.pReverbPreset = pPreset;
				ser.Value("Weight",NewWeighted.fWeight);
				ser.Value("EffectInside",NewWeighted.bFullEffectWhenInside);
				ser.Value("RegID", NewWeighted.RegID);
				m_vecActiveReverbPresetAreas.push_back(NewWeighted);
			}
							
			ser.EndGroup();
		}

		m_bNeedUpdate = true;

	}

}

//////////////////////////////////////////////////////////////////////////
int CReverbManager::OnObstructionTest(const EventPhys* pEvent)
{
	EventPhysRWIResult const* const pRWIResult = (EventPhysRWIResult*)pEvent;
	if (pRWIResult->iForeignData == PHYS_FOREIGN_ID_SOUND_REVERB_OBSTRUCTION)
	{
		unsigned int const nIdx = (unsigned int)pRWIResult->pForeignData;
		if (nIdx < DIRECTIONS_COUNT)
		{
			if (pRWIResult->nHits)
				m_fObstructionTestResults[nIdx] = pRWIResult->pHits[0].dist;
			else
				m_fObstructionTestResults[nIdx] = FLT_MAX;
		}
	}

	return 1;
}

//////////////////////////////////////////////////////////////////////////
// Description:
//	Every time a reverb manager gets updated this method is called.
//	Here we shoot only one ray of DIRECTIONS_COUNT and evaluate the distance in OnObstructionTest.
//	Once we reached the last vector we will start from the beginning
//	The length of the ray being shot is only the distance sound can travel within 0.4 seconds divided by 2
//	Early and late reflection together cover only 0.4 seconds
void CReverbManager::SendRay()
{
	if (m_pSoundSystem && g_SoundCVars.g_fReverbDynamic > 0.0f)
	{
		uint32 const nActiveListenerCount = m_pSoundSystem->GetNumActiveListeners();
		if (nActiveListenerCount == 1)
		{
			// There is just 1 active listener
			IEntity const* const pPlayerEntity = gEnv->pEntitySystem->GetEntity(gEnv->pGame->GetIGameFramework()->GetClientActorId());

			if (pPlayerEntity)
			{
				IListener const* const pListener = m_pSoundSystem->GetListener(m_pSoundSystem->GetClosestActiveListener(pPlayerEntity->GetWorldPos()));
				if (pListener)
				{
					assert (pListener->GetActive());
					m_v3Origin = pListener->GetPosition();

					// Calculate the distance sound travels within 0.4 seconds
					float const fDistance = SONIC_SPEED_METER_PER_SEC * 0.2f; // Use only have the way, sound needs to travel back and forth
					gEnv->pPhysicalWorld->RayWorldIntersection(m_v3Origin, m_v3ObstructionTestVecs[m_nSentIdx]*fDistance, ent_static, rwi_pierceability0|rwi_stop_at_pierceable|rwi_queue, NULL, 1, NULL, 0, (void*)m_nSentIdx, PHYS_FOREIGN_ID_SOUND_REVERB_OBSTRUCTION);

					if(++m_nSentIdx == DIRECTIONS_COUNT)
						m_nSentIdx = 0;
				}
			}
		}
		else if (nActiveListenerCount > 1)
		{
			// There are more than 1 active listeners
			// TODO: This case needs to be handled
			assert(0);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CReverbManager::DrawDynamicReverbDebugInfo(IRenderer* const pRenderer)
{
	IRenderAuxGeom* const pAuxGeom = pRenderer->GetIRenderAuxGeom();
	pAuxGeom->SetRenderFlags(e_Def3DPublicRenderflags);
	ColorB oColor;
	float const fDistance = SONIC_SPEED_METER_PER_SEC * 0.2f;

	// Determine the shortest distance
	float fShortestDistance = FLT_MAX;
	unsigned int nShortestIdx = -1;
	for (unsigned int i = 0; i < DIRECTIONS_COUNT; ++i)
	{
		if (m_fObstructionTestResults[i] < fShortestDistance)
		{
			fShortestDistance	= m_fObstructionTestResults[i];
			nShortestIdx			= i;
		}
	}

	// Now draw all spheres+rays and the closest one red
	for (unsigned int i = 0; i < DIRECTIONS_COUNT; ++i)
	{
		if (i != nShortestIdx)
			oColor.set(255, 255, 0, 255); // Yellow
		else
			oColor.set(255, 0, 0, 255);		// Red

		// Do the actual drawing
		Vec3 const v3Temp1(m_v3ObstructionTestVecs[i]*m_fObstructionTestResults[i]);
		Vec3 const v3Temp2(m_v3Origin+v3Temp1);
		pAuxGeom->DrawSphere(v3Temp2, 0.2f, oColor);
		pAuxGeom->DrawLine(m_v3Origin, oColor, m_v3Origin+m_v3ObstructionTestVecs[i]*fDistance, oColor, 3.0f);
	}
}

void CReverbManager::GetMemoryUsage( ICrySizer *pSizer ) const
{
	SIZER_COMPONENT_NAME(pSizer, "ReverbManager");
	pSizer->AddObject(this, sizeof(*this));	
	pSizer->AddObject(m_ReverbPresets);	
	pSizer->AddObject(m_vecActiveReverbPresetAreas);	
	pSizer->AddObject(m_Sounds);		
}